/**
 * @file   Func.h
 * @author xingyifan
 * @date   2021/08/15 00:29:47
 *
 * @brief  here we declare a class function, to stand for all the functions
 *
 *
 */

#include "Math.h"

using namespace std;

#ifndef __EQUATION__
#define __EQUATION__

class EquationSolver
{
protected:
    double (*f)(double);

public:
    EquationSolver(double (*f)(double)) : f(f) {}

    virtual double solve(double, double) = 0;
};

//二分法
class Bisection : public EquationSolver
{
public:
    Bisection(double (*f)(double)) : EquationSolver(f) {}

    double solve(double u, double v)
    {
        double u_f = f(u), v_f = f(v);
        if (SIGN(u_f) == SIGN(v_f))
        {
            cout << "Same sign!" << endl;
            return INFTY;
        }
        double mid, mid_f;
        //限制最多迭代100次
        for (int i = 0; i < ITERATION; i++)
        {
            mid = (u + v) / 2;
            mid_f = f(mid);
            //根据精度判断退出
            if (fabs(u - v) < ACCURACY || fabs(u_f - v_f) < ACCURACY)
            {
                break;
            }
            else if (SIGN(u_f) == SIGN(mid_f))
            {
                u = mid;
                u_f = f(u);
            }
            else
            {
                v = mid;
                v_f = f(v);
            }
        }
        return mid;
    }
};

//牛顿法
class Newton : public EquationSolver
{
private:
    double (*g)(double);

public:
    Newton(double (*f)(double), double (*g)(double)) : EquationSolver(f), g(g) {}

    double solve(double a, double b)
    {
        double dx, root = (b + a) / 2;
        for (int i = 0; i < ITERATION; i++)
        {
            if (g(root) == 0)
            {
                cout << "Stop" << endl;
                return root;
            }
            dx = f(root) / g(root);
            if (fabs(dx) < ACCURACY)
            {
                break;
            }
            root -= dx;
        }
        return root;
    }
};

//割线法
class Secant : public EquationSolver
{
public:
    Secant(double (*f)(double)) : EquationSolver(f) {}

    double solve(double x_0, double x_1)
    {
        double dx;
        for (int i = 0; i < ITERATION; i++)
        {
            if (f(x_1) - f(x_0) == 0)
            {
                cout << "Stop" << endl;
                return x_1;
            }
            dx = f(x_1) * (x_1 - x_0) / (f(x_1) - f(x_0));
            if (fabs(dx) < ACCURACY || fabs(x_1 - x_0) < ACCURACY)
            {
                break;
            }
            double tmp = x_1;
            x_1 -= dx;
            x_0 = tmp;
        }
        return x_1;
    }
};

#endif